package com.example.demo.util;

import com.example.demo.support.UserSig;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;
import java.util.zip.Deflater;

@Slf4j
public final class UserSigUtils {

    /**
     * 存活时间 单位秒
     */
    private static final int SIG_LIVE_TIME = 360000;

    private static String encryptSig(String sdkAppId, String secret, String user, long currentTime, long expireTime) {
        String contentToBeSigned = "TLS.identifier:" + user + "\n"
            + "TLS.sdkappid:" + sdkAppId + "\n"
            + "TLS.time:" + currentTime + "\n"
            + "TLS.expire:" + expireTime + "\n";
        String alg = "HmacSHA256";
        try {
            Mac instance = Mac.getInstance(alg);
            instance.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), alg));
            byte[] bytes = instance.doFinal(contentToBeSigned.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(bytes);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            log.error("生成用户秘钥出现错误：", e);
            throw new RuntimeException("生成用户秘钥出现错误");
        }
    }

    public static UserSig genUserSig(String sdkAppId, String secret, String user) {
        // 为了保证避免一些不必要的问题
        LocalDateTime expired = LocalDateTime.now().plusSeconds(SIG_LIVE_TIME - 5);
        long currentTime = System.currentTimeMillis() / 1000;
        long expireTime = SIG_LIVE_TIME;
        Gson gson = new Gson();
        Map<String, Object> map = Maps.newHashMap();
        map.put("TLS.ver", "2.0");
        map.put("TLS.identifier", user);
        map.put("TLS.sdkappid", sdkAppId);
        map.put("TLS.expire", expireTime);
        map.put("TLS.time", currentTime);
        map.put("TLS.sig", encryptSig(sdkAppId, secret, user, currentTime, expireTime));
        String json = gson.toJson(map);
        Deflater deflater = new Deflater();
        deflater.setInput(json.getBytes(StandardCharsets.UTF_8));
        deflater.finish();
        byte[] bytes = new byte[2048];
        int length = deflater.deflate(bytes);
        deflater.end();
        return UserSig.of(Base64.getEncoder().encodeToString(Arrays.copyOfRange(bytes, 0, length)), expired);
    }
}
